/*
 * @Description:  node种代码源码
 * @Version: 1.0
 * @Autor: ziwei
 * @Date: 2021-04-06 09:21:46
 * @LastEditors: ziwei
 * @LastEditTime: 2021-04-23 15:17:04
 */
//自己实现require  稍微有点懵 需要反复理解
const fs = require('fs');
const path = require('path');
const vm = require('vm');
function Module(id) {
  this.id = id;
  this.exports = {}
}
Module._extensions = {
  '.js'(module){
    let script = fs.readFileSync(module.id,'utf8');
    let templateFn = `(function(exports,module,require,__dirname,__filename){${script}})`;

    let fn =vm.runInThisContext(templateFn);
    let exports = module.exports;
    let thisValue = exports;
    let filename = module.id;
    let dirname = path.dirname(filename);
    fn.call(thisValue,exports,module,req,dirname,filename);//调用了a模块 module.exports = 100
  }
  ,'json'(module){
    let script = fs.readFileSync(module.id,'utf8');
    module.exports = JSON.parse(script);
  }
}
Module._resolveFilename = function (id) {
  let filePath = path.resolve(__dirname,id);
  let isExists = fs.existsSync(filePath);
  if(isExists) return filePath;
  //尝试添加后缀
  let keys = Object.keys(Module._extensions);//以后Object新出的方法 都会被放到Reflect上
  for(let i=0;i<keys.length;i++){
    let newPath = filePath + keys[i];
    if(fs.existsSync(newPath)) return newPath;
  }
  throw new Error('module not found');
}
function req(filename) {
  filename = Module._resolveFilename(filename);//1.创造一个绝对引用地址，方便后续读取
  let cacheModule = Module._cache[filename]
  if(cacheModule) return Module.exports;//直接将上次缓存的模块对给你 就ok了

  const module = new Module(filename);//2.根据路径创建一个模块
  Module._cache[filename] = module;//最终：缓存模块 根据文件名来缓存
  module.load();//就是让用户module.exports赋值
  return module.exports;//默认就是空对象
}
let a = req('./a');
a = req('./a');
a = req('./a');
console.log(a);
//断点调试
/* let a = require('./a')
console.log(a); */
//1.直接在vs code中调试
//2.可以在chrome种进行调试，方案调试 node --inspect-brk 执行文件
// let a = (function(exports,module,require,__dirname,__firname) {
    
// })('...5个参数')

//1.require方法 ->Module.prototype.require
//2.Module.load加载模块
//3.Moudle._resolveFilename 方法把路径变成了绝对路径 添加后缀名（.js .json）
//4.new Module 拿到绝对路径创造一个模块 this.id exports={}
//5.module.load 对模块进行加载
//6.根据文件后缀 Module._extensions['.js']去做策略加载
//最终返回的exports对象